package com.globox.servlet;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import utils.Sit;
import utils.Theater;

public class TrafficGen extends HttpServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2608993166275913759L;
	private static final String BROWSE_SITS_THEATERS = app_srv_interface.IGlobox.BROWSE_SITS_THEATER;
	private static final int NUM_THEATERS = 1400;
	private static final Object ADD_PURCHASE = app_srv_interface.IGlobox.ADD_PURCHASE;
	private static final Object LIST_THEATERS = app_srv_interface.IGlobox.LIST_THEATERS;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// Use "request" to read incoming HTTP headers (e.g. cookies)
		// and HTML form data (e.g. data the user entered and submitted)

		// Use "response" to specify the HTTP response line and headers
		// (e.g. specifying the content type, setting cookies).

		PrintWriter out = response.getWriter();
		String clientMode = request.getParameter("clientMode");
		String targetType = request.getParameter("targetType");
		String operation = request.getParameter("operation");
		String reqPerSec = request.getParameter("reqPerSec");
		String duration = request.getParameter("duration");

		try {
			startSimulation(clientMode, targetType, operation, reqPerSec,
					duration);
		} catch (Exception e) {
			out.write("Exception " + e + "<br />");
			e.printStackTrace();
		}
	}

	private void startSimulation(String clientMode, String targetType,
			String operation, String reqPerSec, String duration) {

		Integer clientID = -1;
		List<Integer> clients = new ArrayList<Integer>();
		final List<String> theaters = new ArrayList<String>();
		List<String> allTheaters = new ArrayList<String>();

		// get the theaters
		try {
			List<Theater> tmp = searchTheaters("all");
			for (Theater t : tmp)
				allTheaters.add(t.getName());
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		//
		if (clientMode.equals("single")) {
			clientID = new Random().nextInt(1000000);
			clients.add(clientID);
		} else {
			for (int i = 0; i < 1000000; i++)
				clients.add(new Random().nextInt(1000000));
		}
		//
		if (targetType.equals("single")) {
			// get a random one
			String th = allTheaters.get(new Random().nextInt(NUM_THEATERS));
			theaters.add(th);
		} else {
			for (int i = 0; i < new Random().nextInt(NUM_THEATERS); i++) {
				int pos = new Random().nextInt(NUM_THEATERS);
				String t = allTheaters.get(pos);
				theaters.add(t);
			}
		}
		//
		if (operation.equals("purchase")) {
			for (int i = 0; i < clients.size(); i++) {
				Thread t = new Thread(new Runnable() {
					@Override
					public void run() {
						for (final String th : theaters) {
							Thread t2 = new Thread(new Runnable() {
								@Override
								public void run() {
									try {
										List<Sit> sits = getSitsByTheater(th);
										Sit s = sits.get(new Random()
												.nextInt(sits.size()));
										List<Sit> pch = new ArrayList<Sit>();
										pch.add(s);
										addPurchase(th, pch);
									} catch (Exception e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
								}
							});
							t2.start();
						}
					}
				});

				t.start();
			}
		} else {

		}
	}

	private List<Theater> searchTheaters(String query) throws Exception {
		String appSrvPort = "12345";
		String appSrvHost = "localhost";
		if (!appSrvHost.equalsIgnoreCase("")
				&& !appSrvPort.equalsIgnoreCase("")) {

			Socket s = new Socket(appSrvHost, Integer.parseInt(appSrvPort));

			ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
			ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

			oos.writeObject(LIST_THEATERS);
			oos.flush();

			oos.writeObject(query);
			oos.flush();

			// out.write("before getting response" + "<br />");

			@SuppressWarnings("unchecked")
			List<Theater> results = (List<Theater>) ois.readObject();

			// get th generated ID
			// MY_UNIQUE_ID = (Integer) ois.readObject() + "";
			// out.write("after getting response" + "<br />");

			return results;
		} else {
			throw new Exception("Invalid settings-call for server");
		}
	}

	private String addPurchase(String theater, List<Sit> sits) throws Exception {
		String appSrvPort = "12345";
		String appSrvHost = "localhost";
		if (!appSrvHost.equalsIgnoreCase("")
				&& !appSrvPort.equalsIgnoreCase("")) {

			Socket s = new Socket(appSrvHost, Integer.parseInt(appSrvPort));

			ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
			ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

			oos.writeObject(ADD_PURCHASE);
			oos.flush();

			oos.writeObject(theater);
			oos.flush();

			oos.writeObject(sits);
			oos.flush();

			// out.write("before getting response" + "<br />");

			String result = (String) ois.readObject();

			// out.write("after getting response" + "<br />");
			try {
				ois.close();
				oos.close();
				s.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

			return result;
		} else {
			throw new Exception("Invalid settings-call for server");
		}
	}

	private List<Sit> getSitsByTheater(String name) throws Exception {
		String appSrvPort = "12345";
		String appSrvHost = "localhost";
		if (!appSrvHost.equalsIgnoreCase("")
				&& !appSrvPort.equalsIgnoreCase("")) {

			Socket s = new Socket(appSrvHost, Integer.parseInt(appSrvPort));

			ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
			ObjectInputStream ois = new ObjectInputStream(s.getInputStream());

			oos.writeObject(BROWSE_SITS_THEATERS);
			oos.flush();

			oos.writeObject(name);
			oos.flush();

			@SuppressWarnings("unchecked")
			List<Sit> results = (List<Sit>) ois.readObject();

			try {
				ois.close();
				oos.close();
				s.close();
			} catch (Exception e) {
				e.printStackTrace();
			}

			return results;
		} else {
			throw new Exception("Invalid settings-call for server");
		}
	}
}
